package com.cskaoyan.javase.oop1._2reference;

/**
 * 重新认识引用数据类型
 * 我们通过数组的初始化过程,去初步认识了引用数据类型,我们认为引用数据类型在内存中
 * 有两个部分:
 * 1.引用
 * 2.对象
 * 其中对象是实质,但是不能直接访问,我们只能通过引用间接的去访问堆上的对象.栈上的引用通过存储对象的地址和对象产生关系.
 * 但是这种认识会导致,引用数据类型和基本数据类型完全就没有任何关系了,完全是两种没有任何关系的东西.
 * 这不好,我们需要一种方式来统一它们的概念.
 * 我们通过数据类型的基本概念来统一它们的定义.
 * 数据类型的基本概念: 一组数据和基于这种数据的合法操作,共同组成一种数据类型 比如int就有固定的取值和固定的操作
 * 那么引用数据类型是不是这样的呢?
 * 我们会发现,当我们定义了一个类时:
 *      类中的成员变量的集合就是就是数据的集合,而成员方法的集合就是基于这种数据操作的集合
 * 所以,我们定义了一个类就是定义了一种自定义的数据类型,这就是引用数据类型,它和基本数据类型的概念没有本质区别.
 *
 * -----------------
 *
 * 当我们在程序中使用一个基本数据类型时，由于基本数据类型是JVM当中已经预先定义好的（所以基本数据类型叫"内置数据类型"），JVM可以清楚的知道这个基本数据类型变量在内存中的存储方式（占用空间大小、结构等等），JVM能够正常开辟空间，正常给变量初始化赋值。
 *
 * 但是引用数据类型并不是内置数据类型，而是我们自定义的数据类型，要想让JVM帮助我们开辟空间创建引用和对象，JVM怎么知道到底要创建什么呢？难道它未卜先知吗？
 *
 * 显然是不可能未卜先知的,所以JVM在创建某个类的对象之前,肯定需要先了解和认识该类型(比如里面有什么成员变量,有什么成员方法等等),这种JVM认识了解某个类型的过程,称之为"类加载"
 *
 * 关于类加载:
 *      1.类加载的详细过程和具体流程,我们会在后面章节专门学习,这里不做详细讲解.
 *      2.我们需要知道类加载是通过I/O流的形式(把东西从U盘拷到硬盘上,这就是I/O)
 *          把某个类的字节码文件(class)文件读取进JVM内存中的方法区
 *          然后经过一系列操作,JVM就完成了类加载,于是就"认识"了该类型,就可以创建它的对象了
 *
 *  思考:
 *      1.类加载这个过程,和创建对象的过程,谁先谁后?
 *          肯定类加载在前,因为认识类型之后,才能创建对象
 *      2.类加载是同I/O流的形式完成字节码文件的读取的,效率是非常低的,所以:
 *          a.类加载是不管三七二十一,先加载再说,还是等到必须要用的时候加载?
 *              因为效率低,为了提升程序效率,类加载是懒加载的,只有等到一定要加载了,不加载不行了,才会进行类加载
 *
 *          b.在java中,把一定需要进行类加载,一定会触发类加载的场景,称之为"类加载的时机".
 *              目前我们已经知道的类加载的时机有:
 *                  1.new对象
 *                  2.启动某个类的main方法,先类加载这个类,比如要启动Demo类的main方法,必然会先类加载Demo
 *
 *          c.代码一旦运行到类加载时机的场景,就一定会触发该类的类加载
 *
 *     3.在程序的某一次完整运行过程当中,如果多次创建某个类的对象,会触发几次类加载?
 *          在程序的某一次完整运行过程当中,无论是何种手段触发类加载,只会类加载一次.
 *
 *
 * 有了类加载之后,引用数据类型创建对象的过程和数组就有了些许变化,我们再来看一下这个JVM内存模型
 *
 * @since 11:44
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        System.out.println("hello world");
        /*
            启动该类Demo的main方法就会触发该类的类加载
            后面创建对象就不会再触发类加载了
            因为类加载在程序的运行过程中,有且仅有一次
         */
        Demo d = new Demo();
        A a = new A();
        A a2 = new A();
        A a3 = new A();
    }
}
class A{}
